package casbinService

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/Sir-yuChen/funAnalyse/global"
	"github.com/Sir-yuChen/funAnalyse/global/redisEnums"
	"github.com/Sir-yuChen/funAnalyse/model"
	"github.com/Sir-yuChen/funAnalyse/model/common/ApiReturn"
	"github.com/Sir-yuChen/funAnalyse/model/request"
	"github.com/Sir-yuChen/funAnalyse/service/commonService"
	"github.com/Sir-yuChen/funAnalyse/utils"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"gorm.io/gorm"
	"strconv"
	"strings"
)

type StockCasbinRoleRelationResourcesService struct{}

func NewStockCasbinRoleRelationResourcesService() *StockCasbinRoleRelationResourcesService {
	return &StockCasbinRoleRelationResourcesService{}
}

//GetStockCasbinRoleRelationResources 多条件查询
func (u *StockCasbinRoleRelationResourcesService) GetStockCasbinRoleRelationResources(req *model.StockCasbinRoleRelationResourcesModel) (a ApiReturn.ApiReturnCode) {
	var mo []model.StockCasbinRoleRelationResourcesModel
	sql := ""
	obj := model.NewStockCasbinRoleRelationResourcesModel()
	tableName := obj.TableName()
	sqlCondition := utils.ReflectHandleStuct(req)
	if sqlCondition != "" {
		sql = `select * from ` + tableName + ` where ` + sqlCondition
	} else {
		sql = `select * from ` + tableName + ` order by id desc  limit 100 `
	}
	err := global.GVA_DB.Raw(sql).Scan(&mo).Error
	if err != nil {
		global.GVA_LOG.Error("basis Get异常", zap.Any("req", req), zap.Any("sql", sql), zap.Error(err))
		return ApiReturn.ErrSystem
	}
	s := ApiReturn.OK
	s.Data = mo
	return s
}

//InsertStockCasbinRoleRelationResources
func (u *StockCasbinRoleRelationResourcesService) InsertStockCasbinRoleRelationResources(req *model.StockCasbinRoleRelationResourcesModel) (a ApiReturn.ApiReturnCode) {
	err := global.GVA_DB.Model(req).Create(req).Error
	if err != nil {
		global.GVA_LOG.Error("basis insert异常", zap.Any("req", req), zap.Error(err))
		return ApiReturn.ErrSystem
	}
	return ApiReturn.OK
}

//UpdateStockCasbinRoleRelationResources 更新
func (u *StockCasbinRoleRelationResourcesService) UpdateStockCasbinRoleRelationResources(req *model.StockCasbinRoleRelationResourcesModel) (a ApiReturn.ApiReturnCode) {
	if req.Id == 0 {
		return ApiReturn.ErrParam
	}
	err := global.GVA_DB.Model(req).Updates(req).Error
	if err != nil {
		global.GVA_LOG.Error("basis Update异常", zap.Any("req", req), zap.Error(err))
		return ApiReturn.ErrSystem
	}
	return ApiReturn.OK
}

//DelStockCasbinRoleRelationResources 根据ID删除
func (u *StockCasbinRoleRelationResourcesService) DelStockCasbinRoleRelationResources(req *model.StockCasbinRoleRelationResourcesModel) (a ApiReturn.ApiReturnCode) {
	if req.Id == 0 {
		return ApiReturn.ErrParam
	}
	err := global.GVA_DB.Model(req).Where("id = ?", req.Id).Delete(model.StockCasbinRoleRelationResourcesModel{}).Error
	if err != nil {
		global.GVA_LOG.Error("basis Del异常", zap.Any("req", req), zap.Error(err))
		return ApiReturn.ErrSystem
	}
	return ApiReturn.OK
}

// AssigningResources 分配资源
func (u *StockCasbinRoleRelationResourcesService) AssigningResources(r *request.AssigningResourcesRequest, c *gin.Context) (a ApiReturn.ApiReturnCode) {
	/* 分配资源
	1. 当前用户必须有该角色权限
	2. 一个角色可对应多个资源
	3. 生成策略
	*/
	//1. 获取用户ID 查用户详情
	customerId, _ := c.Get("customerId")
	userInfo, err := commonService.GetUserInfoByToken(c)
	if err != nil || userInfo == nil {
		global.GVA_LOG.Error("LeveCompare 获取当前登录用户信息异常", zap.Any("customerId", customerId), zap.Error(err))
		return ApiReturn.ErrSystem
	}
	i, _ := strconv.Atoi(r.RoleId)
	//校验用户是否有当前角色
	apiReturn := NewStockCasbinRoleRelationUserService().GetStockCasbinRoleRelationUser(&model.StockCasbinRoleRelationUserModel{
		RoleId: i,
		UserId: fmt.Sprint(customerId),
		Status: "Y",
	})
	if apiReturn.Code != ApiReturn.OK.Code || apiReturn.Data == nil {
		global.GVA_LOG.Error("AssigningResources 分配资源 当前用户无权限为该用户分配资源", zap.Any("customerId", customerId), zap.Any("request", r))
		return ApiReturn.NoPermission
	}
	apiReturn.Data = nil
	err = global.GVA_DB.Transaction(func(tx *gorm.DB) error {
		//校验用户对分配的资源是否有权限
		var res []model.StockApiResource
		sql := `select * from stock_api_resource where  id in (` + r.ResourcesIds + `)`
		err = tx.Raw(sql).Scan(&res).Error
		if err != nil {
			global.GVA_LOG.Error("AssigningResources 分配资源 校验待分配的资源是否存在", zap.Any("request", r), zap.Error(err))
			return errors.New(ApiReturn.ErrSystem.Msg)
		}
		split := strings.Split(r.ResourcesIds, ",")
		if len(split) != len(res) {
			global.GVA_LOG.Error("AssigningResources 分配资源 部分待分配的资源不存", zap.Any("customerId", customerId), zap.Any("request", r))
			return errors.New(ApiReturn.ErrSystem.Msg)
		}
		//分配某一资源，操作账户必须拥有该资源的角色
		key := fmt.Sprint(customerId) + redisEnums.USER_ROLE_KEY_SUFFIX
		jsonStr, err := global.GVA_REDIS.Get(context.Background(), key).Result()
		var roleIds []model.StockCasbinRoleRelationUserModel
		if err != nil {
			global.GVA_LOG.Error("AssigningResources 获取缓存中用户角色关联关系 异常", zap.Any("customerId", customerId), zap.String("key", key), zap.Error(err))
			return errors.New(ApiReturn.ErrSystem.Msg)
		}
		if err = json.Unmarshal([]byte(jsonStr), &roleIds); err != nil {
			global.GVA_LOG.Error("AssigningResources 数据转换异常 异常", zap.Any("customerId", customerId), zap.String("key", key), zap.Error(err))
			return errors.New(ApiReturn.ErrSystem.Msg)
		}

		for _, r := range split {
			atoi, _ := strconv.Atoi(r)
			for i, v := range roleIds {
				if atoi == v.RoleId {
					break
				}
				if len(roleIds)-1 == i && atoi != v.RoleId {
					var apiInfo model.StockApiResource
					if err = tx.Model(model.StockApiResource{}).Where(" id = ? ", atoi).First(&apiInfo).Error; err != nil {
						global.GVA_LOG.Error("AssigningResources 查询无权限资源异常", zap.Any("customerId", customerId), zap.String("ApiResourceId", r), zap.Error(err))
						return errors.New(ApiReturn.ErrSystem.Msg)
					}
					return errors.New("当前账户对资源:" + apiInfo.ApiName + "无权限")
				}
			}
		}
		//校验完成 开始分配资源
		if e := tx.Where("role_id = ?", r.RoleId).Delete(model.StockCasbinRoleRelationResourcesModel{}).Error; e != nil {
			global.GVA_LOG.Error("AssigningResources 删除所有角色资源关系 异常", zap.Any("customerId", customerId), zap.Any("request", r), zap.Error(e))
			return errors.New(ApiReturn.ErrSystem.Msg)
		}
		//删除策略
		if e := tx.Model(model.CasbinRuleModel{}).Where(" V0 = ?", i).Delete(model.CasbinRuleModel{}).Error; e != nil {
			global.GVA_LOG.Error("AssigningResources 删除所有已经生成的策略 异常", zap.Any("customerId", customerId), zap.Any("request", r), zap.Error(e))
			return errors.New(ApiReturn.ErrSystem.Msg)
		}
		for _, v := range res {
			if e := tx.Model(model.StockCasbinRoleRelationResourcesModel{}).Create(&model.StockCasbinRoleRelationResourcesModel{
				RoleId:     i,
				ResourceId: int(v.Id),
				Status:     v.Status,
			}).Error; e != nil {
				global.GVA_LOG.Error("AssigningResources 建立角色和资源关系 异常", zap.Any("customerId", customerId), zap.Any("request", r), zap.Error(e))
				return errors.New(ApiReturn.ErrSystem.Msg)
			}
			//不要向CasbinRuleModel DB 随意加参数  PType小写p
			if e := tx.Model(model.CasbinRuleModel{}).Create(&model.CasbinRuleModel{
				PType: "p",
				V0:    strconv.Itoa(i),
				V1:    v.ApiPath,
				V2:    v.ApiType,
				V3:    v.Status,
			}).Error; e != nil {
				global.GVA_LOG.Error("AssigningResources 生成策略 异常", zap.Any("customerId", customerId), zap.Any("request", r), zap.Error(e))
				return errors.New(ApiReturn.ErrSystem.Msg)
			}
		}
		return nil
	})
	if err != nil {
		apiReturn.Msg = err.Error()
		return apiReturn
	}
	return ApiReturn.OK
}
